//
// Created by martin on 2/24/22.
//
#include "muduo/base/Mutex.h"
#include "muduo/base/Thread.h"
#include "muduo/base/Condition.h"
#include "muduo/base/Timestamp.h"

#include <vector>
#include <stdio.h>

using namespace muduo;
using namespace std;

MutexLock g_mutex;
vector<int> g_vec;
const int kCount = 10*1000*1000;

int g_count = 0;
int g_threadfunc_count = 0;

int foo() __attribute__ ((__noinline__));

void threadFunc()
{
    for (int i = 0; i < kCount; ++i) {
        MutexLockGuard lock(g_mutex);
        g_vec.push_back(i);
        g_threadfunc_count++;
    }
}

int foo()
{
    MutexLockGuard lock(g_mutex);
    if (!g_mutex.isLockedByThisThread())
    {
        printf("FAIL\n");
        return -1;
    }

    ++g_count;
    return 0;
}

int main()
{
    printf("sizeof pthread_mutex_t: %zd\n", sizeof(pthread_mutex_t));
    printf("sizeof Mutex: %zd\n", sizeof(MutexLock));
    printf("sizeof pthread_cond_t: %zd\n", sizeof(pthread_cond_t));
    printf("sizeof Condition: %zd\n", sizeof(Condition));
    MCHECK(foo());
    if (g_count != 1)
    {
        printf("MCHECK calls twice.\n");
        abort();
    }

    const int kMaxThreads = 8;
    g_vec.reserve(kMaxThreads * kCount);

    Timestamp start(Timestamp::now());
    for (int i = 0; i < kCount; ++i) {
        g_vec.push_back(i);
    }

    printf("single thread without lock %f seconds\n", timeDifference(Timestamp::now(), start));

    start = Timestamp::now();
    threadFunc();
    printf("signle thread with lock %f seconds\n", timeDifference(Timestamp::now(), start));

    // multi-thread invoke threadFunc try to get the same mutex at the same time
    for (int nthreads = 0; nthreads < kMaxThreads; ++nthreads)
    {
        std::vector<std::unique_ptr<Thread>> threads;
        g_vec.clear();
        g_threadfunc_count = 0;
        start = Timestamp::now();
        for (int i = 0; i < nthreads; ++i) {
            threads.emplace_back(new Thread(&threadFunc));
            threads.back()->start();
        }

        for (int i = 0; i < nthreads; ++i) {
            threads[i]->join();
        }
        printf("%d thread(s) with lock %f seconds\n", nthreads, timeDifference(Timestamp::now(), start));
        printf("g_threadfunc_count = %d\n", g_threadfunc_count);
    }
    return 0;
}
